﻿using System.Net;
using System.Text;
using System.Web;
using Microsoft.AspNetCore.Components.Forms;

namespace ApiLib.RCL.Utils;

/// <summary>
/// HTTP工具类
/// </summary>
public static class HttpUtil
{
    static HttpUtil()
    {
        ServicePointManager.SecurityProtocol =
            SecurityProtocolType.Tls |
            SecurityProtocolType.Tls11 |
            SecurityProtocolType.Tls12 |
            SecurityProtocolType.Tls13;
    }

    private static readonly HttpClientHandler ClientHandler = new()
    {
        AllowAutoRedirect = true,
    };

    /// <summary>
    /// http客户端
    /// </summary>
    private static readonly HttpClient Client = new(ClientHandler) { Timeout = TimeSpan.FromMinutes(10) };

    /// <summary>
    /// 新的HttpClient
    /// </summary>
    /// <param name="autoRedirect">自动重定向</param>
    /// <param name="useCookies">使用cookie</param>
    /// <param name="sslCallback">ssl证书</param>
    /// <param name="timeoutMinutes">超时（分钟）</param>
    /// <returns></returns>
    public static HttpClient Builder(bool autoRedirect = true, bool useCookies = true, bool sslCallback = true,
        int timeoutMinutes = 10)
    {
        return new(new HttpClientHandler()
        {
            AllowAutoRedirect = autoRedirect,
        }) { Timeout = TimeSpan.FromMinutes(timeoutMinutes) };
    }

    /// <summary>
    /// 新的HttpClient
    /// </summary>
    /// <param name="handler">处理器</param>
    /// <param name="timeoutMinutes">超时（分钟）</param>
    /// <returns></returns>
    public static HttpClient Builder(HttpClientHandler handler, int timeoutMinutes = 10)
    {
        return new(handler) { Timeout = TimeSpan.FromMinutes(timeoutMinutes) };
    }
    
    /// <summary>
    /// 上传
    /// </summary>
    /// <param name="url"></param>
    /// <param name="file"></param>
    /// <param name="headers"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static async Task<T?> UploadAsync<T>(string url, IBrowserFile file,
        Dictionary<string, string>? headers = null)
    {
        const long maxfilesize = 100 * 1024 * 1024;
        await using var stream = file.OpenReadStream(maxfilesize);
        return await UploadAsync<T>(url, stream, file.Name, headers);
        /*var message = GetRequestMessage(HttpMethod.Post, url, headers);
        using var content = new MultipartFormDataContent();
        var fileContent = new StreamContent(stream);
        content.Add(fileContent, "file", HttpUtility.UrlEncode(file.Name));
        message.Content = content;
        return await SendRequestAsync<T>(message);*/
    }

    /// <summary>
    /// 上传
    /// </summary>
    /// <param name="url"></param>
    /// <param name="fileName">文件名</param>
    /// <param name="headers"></param>
    /// <param name="stream">流</param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static async Task<T?> UploadAsync<T>(string url, Stream stream,string fileName,
        Dictionary<string, string>? headers = null)
    {
        var message = GetRequestMessage(HttpMethod.Post, url, headers);
        using var content = new MultipartFormDataContent();
        const long maxfilesize = 100 * 1024 * 1024;
        var fileContent = new StreamContent(stream);
        content.Add(fileContent, "file", HttpUtility.UrlEncode(fileName));
        message.Content = content;
        return await SendRequestAsync<T>(message);
    }

    /// <summary>
    /// 下载文件
    /// </summary>
    /// <param name="url"></param>
    /// <param name="body"></param>
    /// <param name="headers"></param>
    /// <param name="isPost"></param>
    /// <returns></returns>
    public static async Task<Stream?> DownloadAsync(string url, Dictionary<string, string>? headers = null,
        bool isPost = false, object? body = null)
    {
        var message = GetRequestMessage(isPost? HttpMethod.Post: HttpMethod.Get, url, headers);
        if (isPost)
        {
            message.Content = new StringContent(body.Serialize(), Encoding.UTF8, "application/json");
        }

        try
        {
            var responseMessage = await Client.SendAsync(message);
            return await responseMessage.Content.ReadAsStreamAsync();
        }
        catch (HttpRequestException e)
        {
            e.Message.LogError();
            return null;
        }
    }

    /// <summary>
    /// 下载文件
    /// </summary>
    /// <param name="url"></param>
    /// <param name="body"></param>
    /// <param name="headers"></param>
    /// <param name="isPost"></param>
    /// <returns></returns>
    public static async Task<byte[]?> DownloadByteAsync(string url, Dictionary<string, string>? headers = null,
        bool isPost = false, object? body = null)
    {
        var message = GetRequestMessage(isPost? HttpMethod.Post: HttpMethod.Get, url, headers);
        if (isPost)
        {
            message.Content = new StringContent(body.Serialize(), Encoding.UTF8, "application/json");
        }

        try
        {
            var responseMessage = await Client.SendAsync(message);
            return await responseMessage.Content.ReadAsByteArrayAsync();
        }
        catch (HttpRequestException e)
        {
            e.Message.LogError();
            return null;
        }
    }

    /// <summary>
    /// GET请求
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="headers">请求头</param>
    /// <returns></returns>
    public static async Task<HttpResult> HttpGetAsync(string url, Dictionary<string, string>? headers = null)
    {
        var message = GetRequestMessage(HttpMethod.Get, url, headers);
        return await SendRequestAsync(message);
    }

    /// <summary>
    /// GET请求
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="headers">请求头</param>
    /// <returns></returns>
    public static async Task<T?> HttpGetAsync<T>(string url, Dictionary<string, string>? headers = null)
    {
        var message = GetRequestMessage(HttpMethod.Get, url, headers);
        return await SendRequestAsync<T>(message);
    }


    /// <summary>
    /// Delete请求
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="headers">请求头</param>
    /// <returns></returns>
    public static async Task<HttpResult> HttpDeleteAsync(string url, Dictionary<string, string>? headers = null)
    {
        var message = GetRequestMessage(HttpMethod.Delete, url, headers);
        return await SendRequestAsync(message);
    }


    /// <summary>
    /// Delete请求
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="headers">请求头</param>
    /// <returns></returns>
    public static async Task<T?> HttpDeleteAsync<T>(string url, Dictionary<string, string>? headers = null)
    {
        var message = GetRequestMessage(HttpMethod.Delete, url, headers);
        return await SendRequestAsync<T>(message);
    }

    /// <summary>
    /// POST请求
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="headers">请求头</param>
    /// <param name="body">内容</param>
    /// <param name="type">请求体类型</param>
    /// <returns></returns>
    public static async Task<HttpResult> HttpPostAsync(string url, Dictionary<string, string>? headers = null,
        object? body = null, HttpContentType type = HttpContentType.Json)
    {
        var message = GetRequestMessage(HttpMethod.Post, url, headers, body, type);
        // message.Content = new StringContent(body.Serialize(), Encoding.UTF8, type.GetString());
        // message.BuildContent(body, type);
        return await SendRequestAsync(message);
    }


    /// <summary>
    /// POST请求
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="headers">请求头</param>
    /// <param name="body">内容</param>
    /// <param name="type">请求体类型</param>
    /// <returns></returns>
    public static async Task<T?> HttpPostAsync<T>(string url, Dictionary<string, string>? headers = null,
        object? body = null, HttpContentType type = HttpContentType.Json)
    {
        var message = GetRequestMessage(HttpMethod.Post, url, headers, body, type);
        // message.Content = new StringContent(body.Serialize(), Encoding.UTF8, type.GetString());
        // message.BuildContent(body, type);
        return await SendRequestAsync<T>(message);
    }


    /// <summary>
    /// POST请求，表单提交，文件上传
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="headers"></param>
    /// <param name="body">内容</param>
    /// <returns></returns>
    public static async Task<T?> PostFormAsync<T>(string url, Dictionary<string, string>? headers = null,
        MultipartFormDataContent? body = null)
    {
        var message = GetRequestMessage(HttpMethod.Post, url, headers);
        message.Content = body;
        return await SendRequestAsync<T>(message);
    }

    /// <summary>
    /// POST请求，表单提交，文件上传
    /// </summary>
    /// <param name="url">地址</param>
    /// <param name="headers"></param>
    /// <param name="body">内容</param>
    /// <returns></returns>
    public static async Task<HttpResult> PostFormAsync(string url, Dictionary<string, string>? headers = null,
        MultipartFormDataContent? body = null)
    {
        var message = GetRequestMessage(HttpMethod.Post, url, headers);
        message.Content = body;
        return await SendRequestAsync(message);
    }

    /// <summary>
    /// 发送请求
    /// </summary>
    /// <param name="message"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    private static async Task<T?> SendRequestAsync<T>(HttpRequestMessage message)
    {
        try
        {
            var responseMessage = await Client.SendAsync(message);
            if (responseMessage.IsSuccessStatusCode)
            {
                var result = await responseMessage.Content.ReadAsStringAsync();
                return result.Deserialize<T>();
            }
        }
        catch (HttpRequestException e)
        {
            e.Message.LogError();
        }

        return default;
    }


    /// <summary>
    /// 发送请求
    /// </summary>
    /// <param name="message"></param>
    /// <returns></returns>
    private static async Task<HttpResult> SendRequestAsync(HttpRequestMessage message)
    {
        try
        {
            var responseMessage = await Client.SendAsync(message);
            return new HttpResult
            {
                Code = (int)responseMessage.StatusCode,
                Message = responseMessage.StatusCode.ToString(),
                Content = await responseMessage.Content.ReadAsStringAsync()
            };
        }
        catch (HttpRequestException e)
        {
            e.Message.LogError();
            return new HttpResult { Code = 500, Message = e.Message };
        }
    }

    /// <summary>
    /// 获取请求信息
    /// </summary>
    /// <param name="method">请求方法</param>
    /// <param name="url">地址</param>
    /// <param name="headers">请求头</param>
    /// <param name="body">内容</param>
    /// <param name="type">内容格式</param>
    /// <returns></returns>
    public static HttpRequestMessage GetRequestMessage(HttpMethod method, string url,
        Dictionary<string, string>? headers = null, object? body = null,
        HttpContentType type = HttpContentType.Json)
    {
        ServicePointManager.SecurityProtocol =
            SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
        var message = new HttpRequestMessage(method, url);
        if (headers is { Count: > 0 })
        {
            foreach (var (key, value) in headers)
            {
                message.Headers.Add(key, value);
            }
        }

        if (body != null)
        {
            message.BuildContent(body, type);
        }

        return message;
    }


    /// <summary>
    /// 获取HttpContentType字符串
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public static string GetString(this HttpContentType type)
    {
        return type switch
        {
            HttpContentType.Text => HttpContentTypeString.Text,
            HttpContentType.Stream => HttpContentTypeString.Stream,
            HttpContentType.Form => HttpContentTypeString.Form,
            HttpContentType.MultipartForm => HttpContentTypeString.MultipartForm,
            _ => HttpContentTypeString.Json
        };
    }

    /// <summary>
    /// HttpContentType字符串
    /// </summary>
    private static class HttpContentTypeString
    {
        /// <summary>
        /// 普通文本
        /// </summary>
        public const string Text = "text/plain";

        /// <summary>
        /// JSON字符串
        /// </summary>
        public const string Json = "application/json";

        /// <summary>
        /// 数据流类型(文件流)
        /// </summary>
        public const string Stream = "application/octet-stream";

        /// <summary>
        /// 表单数据(键值对)
        /// </summary>
        public const string Form = "application/x-www-form-urlencoded";

        /// <summary>
        /// 多分部数据
        /// </summary>
        public const string MultipartForm = "multipart/form-data";
    }
}

/// <summary>
/// HttpUtilExtend
/// </summary>
public static class HttpUtilExtend
{
    /// <summary>
    /// Build内容
    /// </summary>
    /// <param name="message"></param>
    /// <param name="body"></param>
    /// <param name="type"></param>
    public static void BuildContent(this HttpRequestMessage message, object? body = null,
        HttpContentType type = HttpContentType.Json)
    {
        var content = "";
        if (type == HttpContentType.Form)
        {
            if (body != null)
            {
                var dictionary = body.ToDictionary();
                foreach (var pair in dictionary)
                {
                    if (content != "")
                    {
                        content += "&";
                    }

                    content += pair.Key + "=" + (pair.Value?.ToString() ?? "");
                }
            }
        }
        else
        {
            content = body.Serialize();
        }

        message.Content = new StringContent(content, Encoding.UTF8, type.GetString());
    }


    /// <summary>
    /// 发送请求
    /// </summary>
    /// <param name="client"></param>
    /// <param name="message"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static async Task<T?> SendRequest<T>(this HttpClient client, HttpRequestMessage message)
    {
        try
        {
            var responseMessage = await client.SendAsync(message);
            if (responseMessage.IsSuccessStatusCode)
            {
                var result = await responseMessage.Content.ReadAsStringAsync();
                return result.Deserialize<T>();
            }
        }
        catch (Exception e)
        {
            e.Message.LogError();
        }

        return default;
    }
}

/// <summary>
/// HTTP请求结果
/// </summary>
public class HttpResult
{
    /// <summary>
    /// 状态码
    /// </summary>
    public int Code { get; init; }

    /// <summary>
    /// 信息
    /// </summary>
    public string Message { get; init; } = "";

    /// <summary>
    /// 内容
    /// </summary>
    public string Content { get; init; } = "";

    /// <summary>
    /// 打印
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        return "[code:" + Code + ",\r\nMessage:" + Message + ",\r\nContent:" + Content + "]";
    }

    /// <summary>
    /// 请求是否成功
    /// </summary>
    public bool IsSuccess => Code == 200;
}

/// <summary>
/// HttpContent类型
/// </summary>
public enum HttpContentType
{
    /// <summary>
    /// 文本
    /// </summary>
    Text,

    /// <summary>
    /// JSON
    /// </summary>
    Json,

    /// <summary>
    /// 流
    /// </summary>
    Stream,

    /// <summary>
    /// 表格
    /// </summary>
    Form,

    /// <summary>
    /// 文件
    /// </summary>
    MultipartForm
}